﻿using GeneticAlgorithm.Interfaces;
using System;
using System.Collections.Generic;

namespace GeneticAlgorithm.Models
{
    class Matrix : IEvolvable<int>
    {
        /// <summary>
        /// 默认构造。随机生成一个基因序列
        /// </summary>
        public Matrix()
        {
            var random = GetRandomArray(MatrixLength, 0, 114514);
            for (int i = 0; i < MatrixLength; i++)
                GeneSequence.Add(new Gene<int>() { GeneInformation = random[i] % 2 });
            UpdateFitness();
        }

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="parameter">包含矩阵中所有元素的一维数组</param>
        public Matrix(object parameter)
        {
            ParseGeneSequence(parameter);
            UpdateFitness();
        }

        public List<Gene<int>> GeneSequence { get; set; } = new List<Gene<int>>(MatrixLength);

        public double? fitness = null;
        public double Fitness
        {
            get
            {
                if (fitness == null)
                    throw new InvalidOperationException("当前对象适应度尚未计算");
                else
                    return fitness.Value;
            }
            set
            {
                throw new InvalidOperationException("不可以设置Finess的值，因为它是只读的");
            }
        }

        public void UpdateFitness()
        {
            double temp = 0;
            for (int i = 0; i < MatrixLength; i++)
                temp += Math.Pow(Target[i] - GeneSequence[i].GeneInformation, 2);
            fitness = temp;
        }

        public void ParseGeneSequence(object parameter)
        {
            if (parameter.GetType() == typeof(int[]) && ((int[])parameter).Length == MatrixLength)
            {
                GeneSequence.Clear();
                for (int i = 0; i < MatrixLength; i++)
                    GeneSequence.Add(new Gene<int>() { GeneInformation = ((int[])parameter)[i] });
            }
            else if (parameter.GetType() == typeof(List<Gene<int>>) && ((List<Gene<int>>)parameter).Count == MatrixLength)
            {
                GeneSequence = parameter as List<Gene<int>>;
            }
            else
                throw new ArgumentException("基因序列参数格式错误");
        }

        /// <summary>
        /// 进化目标
        /// </summary>
        public static readonly int[] Target =
        {
            1, 0, 0, 0, 0, 1,
            0, 1, 0, 0, 1, 0,
            0, 0, 1, 1, 0, 0,
            0, 0, 1, 1, 0, 0,
            0, 1, 0, 0, 1, 0,
            1, 0, 0, 0, 0, 1,
        };

        /// <summary>
        /// 矩阵长度
        /// </summary>
        public static int MatrixLength { get; set; } = 36;

        /// <summary>
        /// 指定范围内的不重复随机数
        /// </summary>
        /// <param name="Number">随机数个数</param>
        /// <param name="minNum">随机数下限</param>
        /// <param name="maxNum">随机数上限</param>
        /// <returns></returns>
        public static List<int> GetRandomArray(int Number, int minNum, int maxNum)
        {
            if (Number >= maxNum - minNum)
                throw new ArgumentException("随机数个数必须小于随机数范围");
            int j;
            List<int> b = new List<int>();
            Random r = new Random();
            for (j = 0; j < Number; j++)
            {
                int i = r.Next(minNum, maxNum + 1);
                if (b.Contains(i))
                    j = j - 1;
                else
                    b.Add(i);
            }
            return b;
        }

        /// <summary>
        /// 将二值图像矩阵信息表示为字符串
        /// </summary>
        /// <returns></returns>
        public string GeneSequenceToString()
        {
            char[] temp = new char[MatrixLength];
            for (int i = 0; i < MatrixLength; i++)
                temp[i] = GeneSequence[i].GeneInformation.ToString()[0];
            return new string(temp);
        }
    }
}
